package model;

import dao.DaoException;
import dao.DaoFactory;
import dao.FilterDao;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

/**
 * 
 * This class is Filter model class
 * 
 * The filter class represents an filter object with its parameters.
 * Filter objects will contain a user id of a user it belongs to and 
 * folder id in which the email meeting filter criteria will be moved to.
 * Filters are used to move emails to a particular folder upon meeting its
 * criteria.
 * 
 * @author Sukhjinder K. Narula
 * @since June 2013
 * @version $Revision: 1.0 $
 */
public class Filter {

	/*
	 * class properties
	 */
	private FilterDao dao;
	private int id;
	private int userId;
	private String title;
	private String subject;
	

	private String to;
	private String from;
	private String body;
	private int folderId;


	/**
	 * Constructor
	 * @param userId int
	 * @param title String
	 * @param to String
	 * @param from String
	 * @param body String
	 * @param folderId int
	 */
	public Filter(int userId, String title, String to, String from, String body,String subject, int folderId) {
		this.id = -1;
		this.userId = userId;
		this.title = title;
		this.to = to;
		this.from = from;
		this.body = body;
		this.subject=subject;
		this.folderId = folderId;
		this.dao = DaoFactory.getFilterDao();
		
	}

	public Filter()
	{
		id=-1;
		userId=-1;
		title="";
	}
	public int getWeight()
	{
		int weight=0;
		
		//to
		if(!to.isEmpty())
		{
			String[] toFilter=this.getTo().split(",");
			weight+=toFilter.length;
			
		}
		
		//from
		if(!from.isEmpty())
		{
			weight++;
			
		}
		
		//subject
		if(!subject.isEmpty())
		{
			String[] subjectFilter=this.getSubject().split("\\s+");
			weight+=subjectFilter.length;
			
		}
			
		//body
		if(!body.isEmpty())
		{
			String[] bodyFilter=this.getBody().split("\\s+");
			weight+=bodyFilter.length;
			
		}
		return weight;
	}

	/**
	 * Gets the filter id
	 * 
	
	 * @return the id */
	public int getId() {
		return id;
	}

	/**
	 * Gets a user id
	 * 
	
	 * @return userId: numeric unique value of the user id */
	public int getUserId() {
		return userId;
	}

	/**
	 * Gets the title field
	 * 
	
	 * @return the title */
	public String getTitle() {
		return title;
	}

	/**
	 * Gets the to field
	 * 
	
	 * @return the to */
	public String getTo() {
		return to;
	}

	/**
	 * Gets the from field
	 * 
	
	 * @return the from */
	public String getFrom() {
		return from;
	}

	/**
	 * Gets the body field
	 * 
	
	 * @return the body */
	public String getBody() {
		return body;
	}

	/**
	 * Gets the folder id field
	 * 
	
	 * @return the folderId */
	public int getFolderId() {
		return folderId;
	}

	/**
	 * Sets the filter id
	 * 
	
	 * @param id int
	 */
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * Sets the user id.
	 * 
	
	 * @param userId int
	 */
	public void setUserId(int userId) {
		this.userId = userId;
	}

	/**
	 * Sets the filter title field
	 * 
	
	 * @param title String
	 */
	public void setTitle(String title) {
		this.title = title;
	}

	/**
	 * Sets the filter to field
	 * 
	
	 * @param to String
	 */
	public void setTo(String to) {
		this.to = to;
	}

	/**
	 * Sets the filter from field
	 * 
	
	 * @param from String
	 */
	public void setFrom(String from) {
		this.from = from;
	}

	/**
	 * Sets the filter body field
	 * 
	
	 * @param body String
	 */
	public void setBody(String body) {
		this.body = body;
	}

	/**
	 * Sets the folder id field
	 * 
	
	 * @param folderId int
	 */
	public void setFolderId(int folderId) {
		this.folderId = folderId;
	}
	
	/**
	 * Returns the subject of the filter
	 * @return
	 */
	public String getSubject() {
		return subject;
	}

	/**
	 * Sets the subject of the filter
	 * @param subject
	 */
	public void setSubject(String subject) {
		this.subject = subject;
	}

	/**
	 * Saves the current state of the filter into the database
	 * 
	
	 * @throws ModelException */
	public void save() throws ModelException {

		if (id == -1) {
			try {
				id = dao.create(getTransferObject());
			} catch (DaoException e) {
				throw new ModelException(e.getMessage());
			}
		} else {
			try {
				dao.update(getTransferObject());
			} catch (DaoException e) {
				throw new ModelException(e.getMessage());
			}
		}
	}

	/**
	 * Creates string hash map of properties
	 * 
	
	 * @return a String representation of the properties. */
	public HashMap<String, String> getTransferObject() {

		HashMap<String, String> toReturn = new HashMap<String, String>();
		toReturn.put("Id", String.valueOf(id));
		toReturn.put("UserId", String.valueOf(userId));
		toReturn.put("Title", title);
		toReturn.put("Subject", subject);
		toReturn.put("ToEmail", to);
		toReturn.put("FromEmail", from);
		toReturn.put("Body", body);
		toReturn.put("FolderId", String.valueOf(folderId));
		return toReturn;
	}

	/**
	 * Deletes the filter from the database
	 * 
	
	 * @throws ModelException
	 * @throws DaoException */
	public void delete() throws ModelException {
		try {
			dao.delete(id);
		} catch (DaoException e) {
			throw new ModelException(e.getMessage());
		}
	}
	
	
	/**
	 * This method checks if the to of an email matches the filter's to by first
	 * breaking down the email and filter's to fields and then proceeding to check
	 * @param to email's to
	 * @return boolean value of matched or not
	 */
	private boolean toIsMatched(String to){
		String[] toFromEmail=to.split(",");
		String[] toFromFilter=this.getTo().split(",");
		
		List<String> toFromEmailAsList=Arrays.asList(toFromEmail);
		
		
		for(int i=0;i<toFromFilter.length;i++)
		{
			if(toFromEmailAsList.contains(toFromFilter[i]))
					{
				continue;
					}
			else
				return false;
		}
			return true;	
	}
	
	/**
	 * This method checks if the from of an email matches the filters from
	 * @param from email's from
	 * @return boolean value of matched or not
	 */
	private boolean fromIsMatched(String from){

		//equals ignore trim
		if(this.from.trim().equalsIgnoreCase(from.trim()))
			return true;
		else
			return false;	
	}
	
	/**
	 * This method checks if the subject of an email matches the filters subject
	 * @param subject email's from
	 * @return boolean value of matched or not
	 */
	private boolean subjectIsMatched(String subject){

		if(subject.trim().toLowerCase().contains(this.subject.trim().toLowerCase()))
			return true;
		else
			return false;	
	}
	
	/**
	 * This method checks of the body of an email matches the filters body
	 * @param body of email 
	 * @return boolean value of matched or not
	 */
	private boolean bodyIsMatched(String body){

		if(body.toLowerCase().contains(this.body.trim().toLowerCase()))
			return true;
		else
			return false;	
	}
	
	/**
	 * This method is used to check if the current filter applies to an email 
	 * @param email parameter to be checked if the filter applies to it or not
	 * @return boolean value indicating if filter applies or not
	 */
	
	public boolean filterApplies(Email email){
		int counter = 0;
		ArrayList<String> criteriaFields = getCriteria();
	
		
		if (criteriaFields.size() == 0){
			return false;
		}

		if (criteriaFields.contains("to") && toIsMatched(email.getTo())){
			counter ++ ;
		}
		
		if (criteriaFields.contains("from") && fromIsMatched(email.getFrom())){
			counter ++ ;
		}
		
		if (criteriaFields.contains("subject") && subjectIsMatched(email.getSubject())){
			counter ++ ;
		}
		
		if (criteriaFields.contains("body") && bodyIsMatched(email.getBody())){
			counter ++ ;
		}
		
		if (counter == criteriaFields.size()){
			return true;
		} else {
			return false;
		}

		
		
		
	}

	/**
	 * This method results the criteria that should be considered for a filter
	 * @return arraylist of criteria as string
	 */
	private ArrayList<String> getCriteria() {
		
		ArrayList<String> result=new ArrayList<String>();
		
		if(!body.isEmpty())
			result.add("body");
		if(!to.isEmpty())
			result.add("to");
		if(!from.isEmpty())
			result.add("from");
		if(!subject.isEmpty())
			result.add("subject");

		return result;
	}


}
